﻿using System;
using System.Collections.Generic;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using UFIDA.U9.Base.Organization;
using UFIDA.U9.WSS.ProxyService.Exceptions;
using UFIDA.U9.WSS.ProxyService.Models;
using UFIDA.U9.WSS.ProxyService.Token;
using UFIDA.U9.WSS.ProxyService.Utils;
using UFSoft.UBF.Util.Log;

namespace UFIDA.U9.WSS.ProxyService.Behavior.Endpoint
{
    public class TokenEndpointBehavior : IDispatchMessageInspector, IEndpointBehavior
    {
        private static readonly ILogger Logger = LoggerManager.GetLogger(typeof(TokenEndpointBehavior));
        private readonly List<IDispatchMessageInspector> _innerInspectors;

        public TokenEndpointBehavior(List<IDispatchMessageInspector> innerInspectors)
        {
            _innerInspectors = innerInspectors;
        }

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            if (WebOperationContext.Current == null)
            {
                throw new WebFaultException(HttpStatusCode.BadRequest);
            }

            InnerCorrelationState innerCorrelationState = new InnerCorrelationState();
            //获取上下文
            innerCorrelationState.SessionObject = GetSessionObject(ref request, channel, instanceContext);
            if (_innerInspectors == null) return innerCorrelationState;
            foreach (IDispatchMessageInspector inspector in _innerInspectors)
            {
                object result = inspector.AfterReceiveRequest(ref request, channel, instanceContext);
                innerCorrelationState.Add(inspector, result);
            }

            return innerCorrelationState;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            InnerCorrelationState innerCorrelationState = correlationState as InnerCorrelationState;
            if (innerCorrelationState == null) return;
            try
            {
                for (int i = _innerInspectors.Count - 1; i >= 0; i--)
                {
                    try
                    {
                        IDispatchMessageInspector inspector = _innerInspectors[i];
                        object beforeReturnObj = innerCorrelationState.GetCorrelationState(inspector);
                        inspector.BeforeSendReply(ref reply, beforeReturnObj);
                    }
                    catch (Exception ex)
                    {
                        Logger.Debug("执行TokenEndpoint Inner Inspector后事件失败:{0}", i);
                        Logger.Debug(ex);
                    }
                }
            }
            finally
            {
                try
                {
                    //清空上下文
                    innerCorrelationState.SessionObject?.ClearSession();
                }
                catch (Exception ex)
                {
                    Logger.Debug("清空Session异常,错误信息:");
                    Logger.Debug(ex);
                }
            }
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }

        /// <summary>
        ///     获取上下文对象
        /// </summary>
        /// <param name="request"></param>
        /// <param name="channel"></param>
        /// <param name="instanceContext"></param>
        /// <returns></returns>
        private static SessionObject GetSessionObject(ref Message request, IClientChannel channel,
            InstanceContext instanceContext)
        {
            if (WebOperationContext.Current == null)
            {
                throw new WebFaultException(HttpStatusCode.BadRequest);
            }

            WebHeaderCollection headers = WebOperationContext.Current.IncomingRequest.Headers;
            //获取Token
            string tokenString = headers[Constant.HeaderAccessTokenName];
            if (string.IsNullOrEmpty(tokenString))
                throw new WSException(ExceptionCodes.TokenIsInEmpty, "token is empty");
            ContextInfo contextInfo;
            //校验Token
            TokenHelper.Instance.ValidateToken(tokenString, out contextInfo);
            SessionObject sessionObject = new SessionObject(contextInfo);
            //切换上下文组织
            string targetOrgCode = headers[Constant.HeaderTargetOrgCodeName];
            if (string.IsNullOrEmpty(targetOrgCode)) return sessionObject;
            Organization targetOrg = Organization.FindByCode(targetOrgCode);
            if (targetOrg == null)
                throw new WSException(ExceptionCodes.ContextOrgCodeNotExist,
                    string.Format("targetOrg:{0} not exist", targetOrgCode));
            SessionObject.SwitchOrg(targetOrg);

            return sessionObject;
        }
    }
}